﻿using System;
using System.Collections.Generic;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Text;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Meta;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Configuration;

namespace Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Pdf
{
    public class BaseModule
    {
        private const string ANNOT_LIST_TITLE = "Information supplémentaire / Annotations";

        #region Internal Members

        /// <summary>Metadata provider</summary>
        protected IMetaProvider metaProvider;

        /// <summary>All different fonts used</summary>
        protected PdfFonts BookFonts;

        /// <summary>ITextSharp document worker </summary>
        protected Document doc;

        /// <summary>generated tables </summary>
        internal List<PdfBookPTable> tables;

        protected string questFullId;

        protected BookConfiguration BookConfig;
        #endregion

        #region Constructor

        public BaseModule(IMetaProvider mp, Document pdfDocument, PdfFonts fontsProvider, BookConfiguration cfg)
        {
            metaProvider = mp;
            BookFonts = fontsProvider;
            doc = pdfDocument;
            tables = new List<PdfBookPTable>();
            BookConfig = cfg;
        }
        #endregion

        #region Properties

        public float TotalWidth
        {
            get
            {
                return doc.PageSize.Width- doc.LeftMargin - doc.RightMargin;
            }
        }

        /// <summary> The generated tables </summary>
        public List<PdfBookPTable> Tables { get { return this.tables; } }

        #endregion

        #region Titles

        /// <summary>Creates a table holding main title text </summary>
        /// <param name="text">title text</param>
        /// <returns>Created table</returns>
        public PdfPTable TableTitle(string text)
        {
            PdfPTable table = new PdfPTable(1);
            table.TotalWidth = TotalWidth;
            Phrase ph = new Phrase(text, BookFonts.FontTitle);
            Anchor target = new Anchor(ph);
            target.Name = text;
            PdfPCell cell = new PdfPCell(target);
            cell.MinimumHeight = 30f;
            cell.Border = Rectangle.NO_BORDER;
            table.AddCell(cell);

            return table;
        }
        
        /// <summary>Creates a table holding a paragraph as separator </summary>
        /// <returns>Created table</returns>
        public void TableParagraph()
        {
            if (BookConfig.AddParagraph)
            {
                PdfPTable table = new PdfPTable(1);
                table.TotalWidth = TotalWidth;
                PdfPCell cell = new PdfPCell(new Paragraph(Environment.NewLine));
                cell.Border = Rectangle.NO_BORDER;
                table.AddCell(cell);
                Tables.Add(new PdfBookPTable(table));
            }
        }


        /// <summary>Creates a table holding Sub title text </summary>
        /// <param name="text">Subtitle text</param>
        /// <returns>Created table</returns>
        protected PdfPTable TableSubTitle(string text)
        {
            PdfPTable table = new PdfPTable(1);
            table.TotalWidth = TotalWidth;
            Phrase ph = new Phrase(text, BookFonts.FontLevelTwo);

            PdfPCell cell = new PdfPCell(ph);
            cell.MinimumHeight = 30f;
            cell.Border = Rectangle.NO_BORDER;
            table.AddCell(cell);

            return table;
        }
        #endregion

        #region Property table
        /// <summary>
        /// Two columns table, as property key and value
        /// </summary>
        /// <returns>created table object</returns>
        protected PdfPTable CreatePropertyTable()
        {
            PdfPTable table = new PdfPTable(2);
            float[] widths = new float[] { 23f, 77f };
            table.SetWidths(widths);
            table.TotalWidth = TotalWidth;
            return table;
        }

        protected void PropertySubTitle(PdfPTable table, string subTitle)
        {

            Phrase ph = new Phrase(subTitle, BookFonts.FontLevelTwo);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.NO_BORDER;
            cell.Colspan = 2;
            cell.SetLeading(0.0f, 1.4f);

            cell.PaddingTop = 8f;
            table.AddCell(cell);
        }
        protected void PropertySubTitle(PdfPTable table, string subTitleProperty, string subTitleContent)
        {

            Phrase ph = new Phrase(subTitleProperty, BookFonts.FontLevelTwo);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.NO_BORDER;
            cell.SetLeading(0.0f, 1.4f);

            cell.PaddingTop = 8f;
            table.AddCell(cell);

            cell = new PdfPCell( new Phrase(subTitleContent, BookFonts.FontLevelTwo));
            cell.Border = Rectangle.NO_BORDER;
            cell.SetLeading(0.0f, 1.4f);

            cell.PaddingTop = 8f;
            table.AddCell(cell);
        }
 

        #endregion

        #region Annotations

        /// <summary>
        /// Four columns table, for annotations
        /// </summary>
        /// <returns>created table object</returns>
        protected void CreateAnnotationTable(List<HierarchyNode> annoList)
        {
            if (annoList.Count > 0)
            {
                float[] widths = new float[] { 8f, 18f, 74f };
                PdfPTable table = new PdfPTable(widths.Length);

                table.SetWidths(widths);
                table.TotalWidth = TotalWidth;
                Tables.Add(new PdfBookPTable(table));

                // title
                Phrase ph = new Phrase(ANNOT_LIST_TITLE, BookFonts.FontLevelTwo);
                PdfPCell cell = new PdfPCell(ph);
                cell.Border = Rectangle.NO_BORDER;
                cell.Colspan = widths.Length;
                table.AddCell(cell);

                // Table Header
                table.AddCell(MakeTitleCell("No"));
                table.AddCell(MakeTitleCell("Type : Title"));
              //  table.AddCell(MakeTitleCell("Title"));
                table.AddCell(MakeTitleCell("Text"));

                // Table rows
                for (int i = 0; i < annoList.Count; ++i)
                    MakeRowAnnotationDetail(table, annoList[i], i+1);

            }
        }

        private void MakeCellAnnotationDetail(PdfPTable table, string text, bool hasBackground)
        {
            MakeCellAnnotationDetail(table, text, hasBackground, null);
        }

        private void MakeCellAnnotationDetail(PdfPTable table, string text, bool hasBackground, string anchorReference)
        {
            Phrase ph = new Phrase(text, BookFonts.FontStandard);
            PdfPCell cell = new PdfPCell(ph);
            if (string.IsNullOrEmpty(anchorReference) == false)
            {
                Anchor click = new Anchor(ph);
                click.Reference = anchorReference;
                cell = new PdfPCell(click);
            }
            
            cell.Border = Rectangle.NO_BORDER;
            cell.SetLeading(0.0f, 1.4f);
            if (hasBackground)
                cell.BackgroundColor = new BaseColor(BookFonts.COLOR_TABLE_ALTERNED);
            cell.PaddingBottom = 4f;
            table.AddCell(cell);
        }

        private void MakeRowAnnotationDetail(PdfPTable table, HierarchyNode node, int index)
        {
            if (string.IsNullOrEmpty(questFullId) == false && node.Id == "QUEST_PRINT")
            {
                MakeRowAnnotationQuestLink(table, node, index);
            }
            else
            {
                string typeTitle = string.IsNullOrEmpty(node.Descr) ? node.Id : node.Id + " : " + node.Descr;
                MakeCellAnnotationDetail(table, index.ToString(), index % 2 == 0);
                MakeCellAnnotationDetail(table, typeTitle, index % 2 == 0);
                MakeCellAnnotationDetail(table, node.Name, index % 2 == 0);
            }
        }

        private void MakeRowAnnotationQuestLink(PdfPTable table, HierarchyNode node, int index)
        {

            string anchorLink = "#" + questFullId + "Q" + ExtractQuestId(node.Descr);
            string typeTitle = "Question Id";
            MakeCellAnnotationDetail(table, index.ToString(), index % 2 == 0);
            MakeCellAnnotationDetail(table, typeTitle, index % 2 == 0);
            MakeCellAnnotationDetail(table, node.Descr, index % 2 == 0, anchorLink);
        }

        protected string ExtractQuestId(string questRange)
        {
            if (questRange == "234.00-02")
            {
                GetQidList(questRange);
            }
            List<string> listId = GetQidList(questRange);
            return listId.Count > 0 ? listId[0] : string.Empty;

            //if (questRange.Length > 0)
            //{
            //    string iid = questRange.Split('_')[0];
            //    qid = iid.Split('/')[0];
            //    while (qid.Length < 5)
            //        qid = "0" + qid;
            //}
        }

        public List<string> GetQidList(string questIdDisplay)
        {
            List<string> listId = new List<string>();

            if (questIdDisplay != null && questIdDisplay.Length > 0)
            {
                // Get groups of questions
                string[] arrGrp = questIdDisplay.Split('_');

                foreach (string sRangeId in arrGrp)
                {
                    string[] arrSeparatorId = sRangeId.Split('/');
                    foreach (string sep in arrSeparatorId)
                    {
                        string[] arrIntervalId = sep.Split('-');
                        bool inInterval = false;
                        foreach (string inter in arrIntervalId)
                        {
                            GetId(listId, inter, inInterval);
                            inInterval = true;
                        }

                    }
                }
            }
            return listId;
        }

        private void GetId(List<string> listId, string tag, bool interval)
        {

            // two char, if interval create all val
            if (tag.Length == 2)
            {
                if (interval)
                {
                    int start = Convert.ToInt32(listId[listId.Count - 1].Substring(3, 2));
                    int end = Convert.ToInt32(tag);
                    string baseId = listId[listId.Count - 1].Substring(0, 3);
                    for (int i = start + 1; i <= end; i++)
                    {
                        listId.Add(baseId + i.ToString().PadLeft(2, '0'));
                    }

                }
                else if (listId.Count > 0)
                    listId.Add(listId[listId.Count - 1].Substring(0, 3) + tag);
            }
            else
            {
                string[] arr = tag.Split('.');
                if (arr.Length == 1)
                {
                    listId.Add(arr[0].PadRight(5, '0'));
                }
                else
                {
                    string s = arr[1].Length != 2 ? arr[1].Substring(0, 1) + "0" : arr[1];
                    s = arr[0] + s;
                    listId.Add(s.PadLeft(5, '0'));
                }

            }

            // 3, 4,5 chars without period, create new id

        }




        #endregion


        /// <summary> Creates table cell used in table header</summary>
        /// <param name="title">text for the cell</param>
        /// <returns>created cell</returns>
        protected PdfPCell MakeTitleCell(string title)
        {
            Phrase ph = new Phrase(title, BookFonts.FontLevelOne);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.LEFT_BORDER;
            cell.BorderColor = BaseColor.WHITE;
            cell.BackgroundColor = new BaseColor(BookFonts.COLOR_TABLE_HEAD);
            cell.PaddingBottom = 3f;
            cell.VerticalAlignment = Element.ALIGN_MIDDLE;
            return cell;
        }
        protected void MakeRowVarDetail(PdfPTable table, string property, string text, bool italicProperty)
        {
            MakeRowVarDetail(table, property, text, null, italicProperty);
        }

        /// <summary> Creates a row content for a two columns property table </summary>
        /// <param name="table">property table</param>
        /// <param name="property">property text</param>
        /// <param name="text">property value text</param>
        /// <param name="italicProperty">if true, shows property text in italic</param>
        protected void MakeRowVarDetail(PdfPTable table, string property, string text, string anchorReference, bool italicProperty)
        {
            // Property name
            Phrase ph = new Phrase(property, italicProperty ?
                BookFonts.FontPropertyItalic : BookFonts.FontProperty);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.NO_BORDER;
            cell.SetLeading(0.0f, 1.2f);
            table.AddCell(cell);

            // Property value text (justified)
            ph = new Phrase(text, BookFonts.FontStandard);
            cell = new PdfPCell(ph);
            if (string.IsNullOrEmpty(anchorReference) == false)
            {
                Anchor click = new Anchor(ph);
                click.Reference = anchorReference;
                cell = new PdfPCell(click);
            }
            

            cell.Border = Rectangle.NO_BORDER;
            cell.SetLeading(0.0f, 1.2f);
            cell.HorizontalAlignment = Element.ALIGN_JUSTIFIED;
            table.AddCell(cell);
        }


        protected PdfPCell MakeTableCell(string text, bool hasBackground)
        {
            return MakeTableCell(text, hasBackground, null, 0);
        }

        protected PdfPCell MakeTableCell(string text, bool hasBackground, string anchorReference, int leftIndent)
        {
            Phrase ph = new Phrase(text, BookFonts.FontStandard);
            PdfPCell cell = new PdfPCell(ph);
            if (string.IsNullOrEmpty(anchorReference) == false)
            {
                Anchor click = new Anchor(ph);
                click.Reference = anchorReference;
                cell = new PdfPCell(click);
            }
            cell.Border = Rectangle.LEFT_BORDER;
            cell.BorderColor = BaseColor.WHITE;
            if (hasBackground)
                cell.BackgroundColor = new BaseColor(BookFonts.COLOR_TABLE_ALTERNED);
            cell.VerticalAlignment = Element.ALIGN_MIDDLE;
            cell.PaddingBottom = 4f;
            cell.PaddingLeft = leftIndent;
            return cell;
        }

        protected PdfPCell MakeTableCellWhite(string text, bool hasBackground)
        {
            Phrase ph = new Phrase(text, BookFonts.FontStandardWhite);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.LEFT_BORDER;
            cell.BorderColor = BaseColor.WHITE;
            if (hasBackground)
                cell.BackgroundColor = new BaseColor(BookFonts.COLOR_TABLE_ALTERNED);
            cell.VerticalAlignment = Element.ALIGN_MIDDLE;
            cell.PaddingBottom = 4f;
            return cell;
        }

        #region FlatHierarchy

        protected PdfPTable CreateFlatListTable(string idTitle)
        {
            PdfPTable table = new PdfPTable(3);
            float[] widths = new float[] { 15f, 15f, 70f };
            table.SetWidths(widths);
            table.TotalWidth = TotalWidth;
            Tables.Add(new PdfBookPTable(table));

            // Table title
            table.AddCell(MakeTitleCell(idTitle));
            table.AddCell(MakeTitleCell("Parent"));
            table.AddCell(MakeTitleCell("Name"));

            return table;
        }

        protected PdfPTable CreateIndentedListTable(string idTitle)
        {
            PdfPTable table = new PdfPTable(2);
            float[] widths = new float[] { 25f, 75f };
            table.SetWidths(widths);
            table.TotalWidth = TotalWidth;
            Tables.Add(new PdfBookPTable(table));

            // Table title
            table.AddCell(MakeTitleCell(idTitle));
            table.AddCell(MakeTitleCell("Name"));

            return table;
        }

        protected PdfPTable CreateIndentedListTable2(string idTitle)
        {
            return CreateIndentedListTable2(idTitle, 0);
        }

        protected PdfPTable CreateIndentedListTable2(string idTitle, int margin)
        {
            PdfPTable table = new PdfPTable(2);
            float[] widths = new float[] { 25f, 75f };
            table.SetWidths(widths);
            table.TotalWidth = TotalWidth - margin;
            Tables.Add(new PdfBookPTable(table));

            // Table title
            //table.AddCell(MakeTableCell(idTitle, true));
            //table.AddCell(MakeTableCell("Name", true));

            table.AddCell(MakeTableCellWhite(idTitle, true));
            table.AddCell(MakeTableCellWhite("Name", true));

            
            return table;
        }
        protected PdfPTable CreateFlatCodelistListTable(string idTitle)
        {
            PdfPTable table = new PdfPTable(2);
            float[] widths = new float[] { 25f, 75f };
            table.SetWidths(widths);
            table.TotalWidth = TotalWidth -50;

            // Table title
            //table.AddCell(MakeTitleCell(idTitle));
            //table.AddCell(MakeTitleCell("Name"));
            table.AddCell(MakeTableCellWhite(idTitle, true));
            table.AddCell(MakeTableCellWhite("Name", true));

            return table;
        }

        protected void ProduceHierarchyFlatList(PdfPTable table, HierarchyNode rootNode, int level, string parentCode, ref int indexNo)
        {
            // Iterates items
            foreach (HierarchyNode childNode in rootNode.Nodes)
            {
                // create row of list
                bool isAlternatedColor = indexNo % 2 == 0 ? true : false;

                // Code Id
                table.AddCell(MakeTableCell(childNode.Id,
                    isAlternatedColor)); //, metaProvider.GetAnchorReferencePrefix() + childNode.Id));

                // Parent
     //           table.AddCell(MakeTableCell(parentCode, isAlternatedColor));

                // Code Name
                table.AddCell(MakeTableCell(childNode.Name, isAlternatedColor));
                ++indexNo;

                // Create lower level Table list
                ProduceHierarchyFlatList(table, childNode, level + 1, childNode.Id, ref indexNo);
            }

        }

        protected void ProduceIndentedList(PdfPTable table, HierarchyNode rootNode, int level, string parentCode, ref int indexNo)
        {
            // Iterates items
            foreach (HierarchyNode childNode in rootNode.Nodes)
            {
                // create row of list
                bool isAlternatedColor = indexNo % 2 == 0 ? true : false;

                // Code Id
                table.AddCell(MakeTableCell(childNode.Id,
                    isAlternatedColor, null, 10*level)); //, metaProvider.GetAnchorReferencePrefix() + childNode.Id));

                // Code Name
                table.AddCell(MakeTableCell(childNode.Name, isAlternatedColor, null, 2));
                ++indexNo;

                // Create lower level Table list
                ProduceIndentedList(table, childNode, level + 1, childNode.Id, ref indexNo);
            }

        }

        #endregion

        public void AddLeading(PdfPTable table, float padding)
        {

            Phrase ph = new Phrase("", BookFonts.FontLevelTwo);
            PdfPCell cell = new PdfPCell(ph);
            cell.Border = Rectangle.NO_BORDER;
            cell.PaddingTop = padding;
            cell.Colspan = 2;
            table.AddCell(cell);
        }

    }

    public class PdfBookPTable
    {
        private PdfPTable pdfTable;

        public bool RequiresNewPage { get; private set; }

        public PdfPTable Table { get { return pdfTable; } }

        public PdfBookPTable(PdfPTable tb)
            : this(tb, false)
        {
        }

        public PdfBookPTable(PdfPTable tb, bool requiresNewPage)
        {
            pdfTable = tb;
            RequiresNewPage = requiresNewPage;
        }
    }


}
